package com.guda.mp.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.app.common.enums.UserStatusEnum;
import com.app.core.base.BaseDao;
import com.app.core.base.BaseServiceImpl;
import com.app.core.base.PageQuery;
import com.app.core.common.AppCons;
import com.app.core.common.NoData;
import com.app.core.common.Result;
import com.app.core.session.UserSession;
import com.app.core.util.MD5Util;
import com.app.core.util.SysConfig;
import com.app.core.web.context.RequestContext;
import com.app.core.web.util.AppContextUtil;
import com.app.util.UUIDUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.guda.mp.dao.LoginUserDao;
import com.guda.mp.dao.SysRoleUserDao;
import com.guda.mp.entity.LoginUser;
import com.guda.mp.entity.SysRoleUser;
import com.guda.mp.service.LoginUserService;
import com.guda.mp.service.PersonService;
import com.guda.mp.service.SysResourceService;
import com.guda.mp.service.SysRoleService;
import com.guda.mp.service.SysRoleUserService;
import com.guda.mp.vo.LoginUserVo;
import com.guda.mp.vo.PersonVo;
import com.guda.mp.vo.SysRoleVo;

@Service
@Transactional
public class LoginUserServiceImpl extends BaseServiceImpl<LoginUser> implements LoginUserService {

    private static final Logger log = LoggerFactory.getLogger(LoginUserServiceImpl.class);

    @Autowired
    private LoginUserDao loginUserDao;
    @Autowired
    private SysRoleUserDao sysRoleUserDao;
    @Autowired
    private SysRoleUserService sysRoleUserService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysResourceService sysResourceService;
    @Autowired
    private PersonService personService;

    @Override
    protected BaseDao<LoginUser> getDao() {
        return this.loginUserDao;
    }

    @Override
    public Result<UserSession> login(String loginName, String password, String code) {
        /*
         * 开始登录
         */
        Result<UserSession> result = toLogin(loginName, password, 2, code);
        if (!result.isSuccess()) {
            return result;
        }

        // 获取用户对象
        UserSession userSession = result.getData();

        /* 存放到公共缓存 APP端 */
        result.getData().setToken(userSession.getSessionId());

        // 获取当前用户的所拥有的菜单项
        loadUserPermission(userSession);

        /* 存放到公共缓存 */
        AppContextUtil.setSessionValue(userSession.getSessionId(), userSession, AppCons.USER_SESSION_TIMEOUT);

        /* 异地登录 */
        // if (AppCons.OTHER_LOGIN_AUTH) {
        // Object obj = AppContextUtil.getSessionValue(AppCons.SESSION_USER_MAPPING + loginName);
        // // 不等于空，并别不等于自己时,告诉之前登陆的账号发生了异地登陆
        // if (obj != null && !userSession.getSessionId().equals(obj.toString())) {
        // UserSession sess = (UserSession) AppContextUtil.getSessionValue(obj.toString());
        // if (sess != null) {
        // sess.setErrorCode(ResultCode.OTHER_LOGIN.getCode());
        // AppContextUtil.setSessionValue(obj.toString(), sess, AppCons.USER_SESSION_TIMEOUT);
        // }
        // }
        // AppContextUtil.setSessionValue(AppCons.SESSION_USER_MAPPING + loginName,
        // userSession.getSessionId(), AppCons.USER_SESSION_TIMEOUT);
        // }

        RequestContext.setUserSession(userSession);
        RequestContext.setLoginUserId(userSession.getUserId());
        RequestContext.setLoginUserName(userSession.getLoginName());
        RequestContext.setUserId(userSession.getUserId());

        UserSession userSession2 = new UserSession();
        userSession2.setSessionId(userSession.getSessionId());
        result.setData(userSession2);

        return result;
    }

    public Result<UserSession> toLogin(String username, String password, Integer userType, String code) {
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            return Result.error("请输入用户名密码!");
        }

        log.info("user login username:{}", username);

        Object loginRetryTimesObj = AppContextUtil.getSessionValue(AppCons.LOGIN_RETRY + username);
        if (loginRetryTimesObj != null && (int) loginRetryTimesObj == AppCons.LOGIN_MAX_RETRY_TIMES) {
            return Result.error("密码错误次数过多，请3分钟后重试!");
        }

        // 查询用户
        LoginUser loginUser = new LoginUser();
        loginUser.setUsername(username);
        List<LoginUser> list = loginUserDao.select(loginUser);
        if (CollectionUtils.isEmpty(list)) {
            return Result.error("用户或密码不正确！");
        }

        loginUser = list.get(0);

        if (CollectionUtils.isEmpty(list)) {
            return Result.error("密码错误次数过多，请3分钟后重试!");
        }

        password = MD5Util.passWordMd5(password.toUpperCase());

        log.info("login: password-2:{}", password);

        if (loginUser == null || !loginUser.getPassword().equalsIgnoreCase(password)) {
            int loginRetryTimes = 1;
            if (loginRetryTimesObj != null) {
                loginRetryTimes = (int) loginRetryTimesObj + 1;
            }

            AppContextUtil.setSessionValue(AppCons.LOGIN_RETRY + username, loginRetryTimes, 180);

            if ((AppCons.LOGIN_MAX_RETRY_TIMES - loginRetryTimes) == 0) {
                return Result.error("密码错误次数过多，请3分钟后重试!");
            }

            return Result.error("用户名或者密码错误，还剩" + (AppCons.LOGIN_MAX_RETRY_TIMES - loginRetryTimes) + "次重试机会!");
        }

        if (loginUser.getStatus() == UserStatusEnum.locked.getCode()) {
            return Result.error("此用户已禁用!");
        }
        if (loginUser.getStatus() == UserStatusEnum.deleted.getCode()) {
            return Result.error("此用户已删除!");
        }

        AppContextUtil.delSessionValue(AppCons.LOGIN_RETRY + username);

        UserSession userSession = new UserSession();
        String sessionKey = UUIDUtil.uuid();
        userSession.setSessionId(sessionKey);
        userSession.setLoginName(username);
        userSession.setUserId(loginUser.getId());
        userSession.setLoginUser(loginUser);
        userSession.setOrgId(loginUser.getOrgId());

        return Result.success(userSession);
    }

    @Override
    public void loadUserPermission(UserSession userSession) {
        Long userId = userSession.getUserId();
        String loginName = userSession.getLoginName();
        if (loginName.equals(SysConfig.get(AppCons.APP_SUPER_ACCOUNT))) {
            userSession.setUserResouceMenu(sysResourceService.selectMenuList(null));
        } else {
            userSession.setUserResouceMenu(sysResourceService.selectMenuList(userId));
            userSession.setUserResouceAll(sysResourceService.selectUserAllResource(userId));
        }
    }

    /**
     * 分页查询所有用户信息
     */
    public Page<LoginUserVo> selectByPage(PageQuery pageQuery, LoginUserVo bean) {
        PageHelper.startPage(pageQuery.getPageNum(), pageQuery.getPageSize());
        if (bean.getOrgId() != null && bean.getOrgId().longValue() == 0) {
            bean.setOrgId(null);
        }
        return (Page<LoginUserVo>) loginUserDao.selectByPage(bean);
    }

    /**
     * 新增用户
     * 
     * @param bean
     * @return
     */
    public Result<NoData> addSave(LoginUserVo bean) {
        bean.setPassword(MD5Util.passWordMd5(MD5Util.getMD5String(bean.getPassword()).toUpperCase()));

        PersonVo personVo = new PersonVo();
        personVo.setName(bean.getName());
        personVo.setAddress(bean.getAddress());
        personVo.setBirthdate(bean.getBirthdate());
        personVo.setGender(bean.getGender());
        personVo.setIdCard(bean.getIdCard());
        personVo.setOrgId(bean.getOrgId());
        personService.add(personVo);

        bean.setPersonId(personVo.getId());

        try {
            bean.setNickName(personVo.getName());
            loginUserDao.add(bean);
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                return Result.error("用户名已存在: " + bean.getUsername());
            } else {
                throw e;
            }
        }

        // 更新用户角色表数据
        if (StringUtils.isNotBlank(bean.getRoleIds())) {
            String[] ids = bean.getRoleIds().split(",");
            for (int i = 0; i < ids.length; i++) {
                SysRoleUser sysRoleUser = new SysRoleUser();
                sysRoleUser.setUserId(bean.getId());
                sysRoleUser.setRoleId(Long.parseLong(ids[i]));
                sysRoleUserService.add(sysRoleUser);
            }
        }
        return Result.success();
    }

    /**
     * 批量删除
     * 
     * @param bean
     * @return
     */
    public Result<NoData> deletes(LoginUserVo bean) {
        String[] ids = bean.getIds().split(",");
        for (int i = 0; i < ids.length; i++) {
            LoginUser loginUser = new LoginUser();
            loginUser.setId(Long.parseLong(ids[i]));
            loginUser.setStatus(3);
            loginUserDao.updateById(loginUser);
        }
        return Result.success();
    }

    /**
     * 通过用户ID查询该用户的拥有哪些角色
     * 
     * @param id
     * @return
     */
    public Map<String, Object> selectRoleByUserId(Long id) {
        Map<String, Object> map = new HashMap<String, Object>();
        String ids = "";
        List<SysRoleVo> dataList = sysRoleService.selectRoleByUserId(id);
        if (CollectionUtils.isEmpty(dataList)) {
            map.put("ids", "");
        } else {
            for (int i = 0; i < dataList.size(); i++) {
                ids = ids + dataList.get(i).getId() + ",";
            }
            map.put("ids", ids.substring(0, ids.length() - 1));
        }
        return map;
    }

    /**
     * 更新用户信息
     * 
     * @param bean
     * @return
     */
    public Result<NoData> updateSave(LoginUserVo bean) {
        List<Long> oldRole = new ArrayList<Long>();
        List<Long> newRole = new ArrayList<Long>();
        if (StringUtils.isNotBlank(bean.getPassword())) {
            bean.setPassword(MD5Util.passWordMd5(MD5Util.getMD5String(bean.getPassword()).toUpperCase()));
        } else {
            // null代表不修改
            bean.setPassword(null);
        }
        try {
            bean.setNickName(bean.getName());
            loginUserDao.updateById(bean);
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                return Result.error("用户名已存在: " + bean.getUsername());
            } else {
                throw e;
            }
        }

        LoginUser loginUser = loginUserDao.selectById(bean.getId());

        PersonVo personVo = new PersonVo();
        personVo.setId(loginUser.getPersonId());
        personVo.setName(bean.getName());
        personVo.setAddress(bean.getAddress());
        personVo.setBirthdate(bean.getBirthdate());
        personVo.setGender(bean.getGender());
        personVo.setIdCard(bean.getIdCard());
        personService.updateById(personVo);

        List<SysRoleVo> dataList = sysRoleService.selectRoleByUserId(bean.getId());

        String[] roleids = null;
        if (StringUtils.isBlank(bean.getRoleIds())) {
            roleids = new String[] {};
        } else {
            roleids = bean.getRoleIds().split(",");
        }
        // 取出原来的用户角色
        for (int i = 0; i < dataList.size(); i++) {
            oldRole.add(dataList.get(i).getId());
        }
        // 判断哪些是新增加的角色，哪些是要废弃的角色
        for (int i = 0; i < roleids.length; i++) {
            if (oldRole.indexOf(Long.parseLong(roleids[i])) >= 0) {
                oldRole.remove(oldRole.indexOf(Long.parseLong(roleids[i])));
            } else {
                newRole.add(Long.parseLong(roleids[i]));
            }
        }
        // 添加新增近来的角色
        for (int i = 0; i < newRole.size(); i++) {
            SysRoleUser sysRoleUser = new SysRoleUser();
            sysRoleUser.setUserId(bean.getId());
            sysRoleUser.setRoleId(newRole.get(i));
            sysRoleUserService.add(sysRoleUser);
        }
        // 删除原来废弃的角色（是物理删除不是逻辑删除）
        for (int i = 0; i < oldRole.size(); i++) {
            sysRoleUserService.deleteById(oldRole.get(i));
        }
        return Result.success();
    }

    /**
     * 修改密码
     * 
     * @param oldPassWord
     * @param newPassWord
     * @param confirmPassWord
     * @return
     */
    public Result<NoData> updatePassWord(String oldPassWord, String newPassWord) {
        if (StringUtils.isBlank(oldPassWord) || StringUtils.isBlank(newPassWord)) {
            return Result.error("请输入完整数据！");
        }
        // 校验密码强度
        if (newPassWord.length() < 5) {
            return Result.error("密码长度至少是6位, 且必须包含数字和字母。");
        }
        // 校验密码强度
        if (newPassWord.length() > 30) {
            return Result.error("密码长度不能超过30位");
        }

        boolean bb = (newPassWord.matches(".*?[a-z]+.*?") || newPassWord.matches(".*?[A-Z]+.*?"))
            && newPassWord.matches(".*?[\\d]+.*?");
        if (!bb) {
            return Result.error("密码必须包含数字和字母");
        }
        LoginUser user = loginUserDao.selectById(RequestContext.getUserSession().getLoginUser().getId());
        // 判断原密码是否相等
        if (!MD5Util.passWordMd5(oldPassWord.toUpperCase()).equalsIgnoreCase(user.getPassword())) {
            return Result.error("原密码输入错误，请重试！");
        }
        user.setPassword(MD5Util.passWordMd5(MD5Util.getMD5String(newPassWord).toUpperCase()));
        loginUserDao.updateById(user);

        return Result.success();
    }

    @Override
    public String getUserRoles(Long loginUserId) {
        SysRoleUser bean = new SysRoleUser();
        bean.setUserId(loginUserId);
        List<SysRoleUser> list = sysRoleUserDao.select(bean);
        if (CollectionUtils.isEmpty(list)) {
            return "";
        }
        StringBuilder roleIds = new StringBuilder();
        for (SysRoleUser sysRoleUser : list) {
            roleIds.append(sysRoleUser.getRoleId()).append(",");
        }

        roleIds.delete(roleIds.length() - 1, roleIds.length());

        return roleIds.toString();
    }

}
